package com.jvm.binary.initialize.invokedynamic;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;

/**
 * MethodHandlesDemo02..
 *
 * Q: How to invoke super-super method
 *
 * <href="https://my.oschina.net/floor/blog/1535062">jdk1.8严格模式</>
 *
 *
 * reflect包     java语言层次
 * invoke包区别   jvm层面，其他语言调用
 *
 * jdk 1.7用户book可以使用，jdk1.8不行
 *
 * @author Lizhong
 * @date 2019/3/18
 */


public class MethodHandlesDemo02 {
    class GrandParent {
        void hello() {
            System.out.println("I'm hello GrandParent");
        }
    }

    class Parent extends GrandParent {
        @Override
        void hello() {
            System.out.println("I'm hello Parent");
        }
    }

    class Child extends Parent {
        /**
         * Code 实现 调用超类方法
         */
        @Override
        void hello() {
            // System.out.println("I'm hello Child" );
            // 第一步 调用Parent方法 ，SoEasy
            // super.hello();
            // 第二部 调用GrandParent
            //bookUseFail();
            zhihu();

        }

        /**
         *      IMPL_LOOKUP 是用来判断私有方法是否被信任的标识，用来控制访问权限的.默认是false,
         *      默认情况下findSpecial方法中的最后一个参数Class<?> specialCaller 有一个校验 checkSpecialCaller,
         *      如果当前的lookup的类和specialCaller不一致的话就会检测不通过,
         *      IMPL_LOOKUP.setAccessible(true);设置为true之后，(MethodHandles.Lookup) IMPL_LOOKUP.get(null)这是获取一个Lookup，
         *      这种方式返回的allowedModes为-1 这样的话就可以绕过检查，从而执行执行传入specialCaller类中的方法，当然也有风险，舍弃了强校验，很容易抛出NoSuchMethodError.
         */
        private void zhihu() {
            MethodType methodType = MethodType.methodType(void.class);
            // IMPL_LOOKUP Metho
            try {
                Field impl_lookup = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
                impl_lookup.setAccessible(true);
                MethodHandles.Lookup lookup = (MethodHandles.Lookup) impl_lookup.get(null);
                MethodHandle hello = lookup.findSpecial(GrandParent.class, "hello", methodType, getClass());
                hello.invoke(this);
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }

        /**
         * 仅适合于1.7
         */
        private void bookUseFail() {
            try {
                MethodType methodType = MethodType.methodType(void.class);
                MethodHandle hello = MethodHandles.lookup().findSpecial(GrandParent.class, "hello", methodType, GrandParent.class);
                hello.invoke(this);
            } catch (Exception e) {

            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
    }


    public static void main(String[] args) {
        Child child = new MethodHandlesDemo02().new Child();
        child.hello();
    }
}
